package com._4cmd.conf;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultConfigurationImpl implements Configuration {
	
	private static DefaultConfigurationImpl instance;

    private static final String CONFIG_FILE_PREFIX = "CONFIG_FILE_";
    private static final String CONFIG_SUFFIX_NAME = "_NAME";
    private static final String CONFIG_SUFFIX_DYNAMIC = "_DYNAMIC_LOAD";

    private static final String DEBUG_GLOBAL = "enable";


    private Map<String, PropFile> propFiles = new ConcurrentHashMap<String, PropFile>();
    
    public static DefaultConfigurationImpl getInstance(){
    	if(null == instance){
    		synchronized(DefaultConfigurationImpl.class){
    			if(null == instance){
    				try {
						instance = new DefaultConfigurationImpl();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    			}
    		}
    	}
    	return instance;
    }

    private DefaultConfigurationImpl() throws IOException {
        Properties properties = null;
        InputStream is = null;
        try {
            String _4todoHome = System.getProperty(EnvConstants.APP_HOME);
            if (_4todoHome != null) {
                File configurationFile = new File(_4todoHome + "/conf/main.properties");
                is = new FileInputStream(configurationFile);
            } else {
                is = this.getClass().getResourceAsStream("/conf/main.properties");
            }
            properties = new Properties();
            properties.load(is);
        } finally {
            try {
                is.close();
            } catch (Exception ex) {

            }
        }
        Set<Map.Entry<Object, Object>> propEntries = properties.entrySet();
        Map<String, PropFile> index2name = new HashMap<String, PropFile>();
        for (Map.Entry<Object, Object> entry : propEntries) {
            String key = (String) entry.getKey();
            if (!key.startsWith(CONFIG_FILE_PREFIX)) continue;
            key = key.substring(CONFIG_FILE_PREFIX.length());
            String idx;
            if (key.indexOf("_") > 0)
                idx = key.substring(0, key.indexOf("_"));
            else
                idx = key;
            String value = (String) entry.getValue();
            if (null == index2name.get(idx))
                index2name.put(idx, new PropFile());
            PropFile propFile = index2name.get(idx);
            if (idx.equals(key))
                propFile.fileName = value;
            else if (key.endsWith(CONFIG_SUFFIX_NAME))
                propFile.name = value;
            else if (key.endsWith(CONFIG_SUFFIX_DYNAMIC))
                propFile.dynamicLoad = Boolean.parseBoolean(value);
        }
        for (PropFile propFile : index2name.values()) loadPropFile(propFile);
    }


    private void loadPropFile(PropFile propFile) {
        synchronized (propFile.fileName.intern()) {
            if (System.currentTimeMillis() - propFile.refreshTime <= 30000) {
                return;
            }

            InputStream is = null;
            try {
                String _4todoHome = System.getProperty(EnvConstants.APP_HOME);
                if (_4todoHome != null) {
                    File configurationFile = new File(_4todoHome + "/conf/" + propFile.fileName);
                    is = new FileInputStream(configurationFile);
                } else {
                    is = this.getClass().getResourceAsStream("/conf/" + propFile.fileName);
                }

                propFile.props.load(is);
                propFile.refreshTime = System.currentTimeMillis();
                propFiles.put(propFile.name, propFile);
            } catch (IOException ex) {
                throw new RuntimeException("Can not load configuration file " + propFile.fileName + ". Exception is: " + ex.getMessage());
            } finally {
                try {
                    is.close();
                } catch (Exception ex) {

                }
            }
        }
    }


    /* (non-Javadoc)
	 * @see com.mycollabs.common.config.Configuration#getBoolean(java.lang.String, java.lang.String)
	 */
    public boolean getBoolean(String typeName, String propName) {
        String value = get(typeName, propName);
        if (value == null)
            return false;
        return "true".equalsIgnoreCase(value.trim());
    }

    /* (non-Javadoc)
	 * @see com.mycollabs.common.config.Configuration#getInt(java.lang.String, java.lang.String)
	 */
    public int getInt(String typeName, String propName) {
        String value = get(typeName, propName);
        return Integer.parseInt(value);
    }

    /* (non-Javadoc)
	 * @see com.mycollabs.common.config.Configuration#getDouble(java.lang.String, java.lang.String)
	 */
    public double getDouble(String typeName, String propName) {
        String value = get(typeName, propName);
        return Double.parseDouble(value);
    }

    /* (non-Javadoc)
	 * @see com.mycollabs.common.config.Configuration#get(java.lang.String, java.lang.String)
	 */
    public String get(String typeName, String propName) {
        return getProps(typeName).getProperty(propName);
    }

    private static class PropFile {
        Properties props = new Properties();
        String fileName;
        String name;
        boolean dynamicLoad = false;
        long refreshTime = 0;
    }

    public boolean isDebugEnabled(String featureName) {
        boolean globalEnabled = getBoolean("debug", DEBUG_GLOBAL);
        if (get("debug", featureName) == null) {
            return globalEnabled;
        }
        boolean enabled = getBoolean("debug", featureName);

        return enabled || globalEnabled;
    }

    public Properties getProps(String typeName) {
        PropFile file = propFiles.get(typeName);
        if (file.dynamicLoad) {
            if (System.currentTimeMillis() - file.refreshTime > 30000)
                loadPropFile(file);
        }
        return file.props;
    }


}
